/******************************************************************************
 * Copyright (C) 2015  671643387@qq.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *****************************************************************************/

#include "TcpDispatcherCluster.h"
#include <memory>
#include <UGame/Base/AtomicValue.h>
#include <UGame/System/Runnable.h>
#include <UGame/System/Thread.h>
#include <UGame/System/Event.h>
#include "TcpDispatcher.h"

namespace UGame {
namespace Net {

    class TcpDispatcherCluster::TcpDispatcherRunnable : public System::Runnable
    {
    public:
        TcpDispatcherRunnable(void)
            : _running(true)
            , _thread()
            , _startEvent()
            , _load(0)
            , _dispatcher()
        {

        }

        virtual ~TcpDispatcherRunnable(void)
        {

        }

        bool Start(void)
        {
            if (!_dispatcher.Open()) {
                return false;
            }
            if (!_thread.Start(this)) {
                return false;
            }
            _startEvent.Wait();
            return true;
        }

        void Close(void)
        {
            UASSERT(_running);
            _running = false;
        }

        void Join(void)
        {
            _thread.Join();
        }

        std::uint32_t GetLoad(void) {
            return _load;
        }

        TcpDispatcher& GetDispatcher(void) {
            return _dispatcher;
        }

        virtual void Run(void)
        {
            _startEvent.Set();
            while (_running) {
                _dispatcher.Update();
                System::Thread::Sleep(1);
            }
        }

    private:
        volatile bool _running;
        System::Thread _thread;
        System::Event _startEvent;
        AtomicValue_UInt32 _load;
        TcpDispatcher _dispatcher;
    };

    TcpDispatcherCluster::TcpDispatcherCluster(void)
        : _dispatchers()
    {
    }

    TcpDispatcherCluster::~TcpDispatcherCluster(void)
    {

    }

    bool TcpDispatcherCluster::Start(int _Workers)
    {
        for (int _I = 0; _I < _Workers; ++_I)
        {
            std::auto_ptr<TcpDispatcherRunnable> _Runnable(new TcpDispatcherRunnable);
            if (_Runnable.get() && _Runnable->Start()) {
                _dispatchers.push_back(_Runnable.release());
            }
            break;
        }

        return _dispatchers.size() == _Workers;
    }

    void TcpDispatcherCluster::Close(void)
    {
        for (TcpDispatcherRunnableArray::iterator _Iter = _dispatchers.begin();
            _Iter != _dispatchers.end();) {
            std::auto_ptr<TcpDispatcherRunnable> _Runnable((*_Iter));
            _Runnable->Close();
            _Runnable->Join();
            _Iter = _dispatchers.erase(_Iter);
        }
    }

    TcpDispatcher& TcpDispatcherCluster::GetDispatcher(void)
    {
        std::uint32_t _LoadMin = UINT_MAX;
        int _Index = 0;
        for (int _I = 0; _I < _dispatchers.size(); ++_I)
        {
            std::uint32_t _Load = _dispatchers[_I]->GetLoad();
            if (_Load < _LoadMin) {
                _LoadMin = _Load;
                _Index = _I;
            }
        }
        return _dispatchers[_Index]->GetDispatcher();
    }

    void TcpDispatcherCluster::_Uninitialize()
    {
        Close();
    }
}}